package com.llb666.shop.payment.api.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.llb666.shop.payment.domain.entity.PreOrderResult;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.llb666.common.core.enums.PayMethod;
import com.llb666.common.core.enums.PaymentStatus;
import com.llb666.common.core.exception.AppException;
import com.llb666.common.core.web.error.CommonError;
import com.llb666.common.core.web.response.BaseResponse;
import com.llb666.common.core.web.response.DataResponse;
import com.llb666.common.redis.service.RedisService;
import com.llb666.shop.payment.api.dto.MerchantOrdersDto;
import com.llb666.shop.payment.api.vo.PaymentInfoVo;
import com.llb666.shop.payment.domain.entity.PayOrders;
import com.llb666.shop.payment.domain.service.PaymentOrderService;
import com.llb666.shop.payment.domain.service.WxOrderService;
import com.llb666.shop.payment.infrastructure.config.AliPayConfig;
import com.llb666.shop.payment.infrastructure.config.WXPayConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

@Tag(name = "订单支付相关接口")
@RestController
@RequestMapping(value = "payment")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PaymentController {

    final static Logger log = LoggerFactory.getLogger(PaymentController.class);

    public final RedisService redisService;
    private final WXPayConfig wxPayConfig;
    private final AliPayConfig aliPayConfig;
    private final PaymentOrderService paymentOrderService;
    private final WxOrderService wxOrderService;

    /**
     * 接受商户订单信息，保存到自己的数据库
     */
    @PostMapping("/createMerchantOrder")
    @Operation(summary = "保存商户订单信息")
    public BaseResponse createMerchantOrder(@RequestBody MerchantOrdersDto merchantOrdersDto,
                                            HttpServletRequest request,
                                            HttpServletResponse response) throws Exception {
        // 入参检验.
        check(merchantOrdersDto);
        // 保存传来的商户订单信息.
        boolean isSuccess;
        try {
            isSuccess = paymentOrderService.createPaymentOrder(merchantOrdersDto);
        } catch (Exception e) {
            e.printStackTrace();
            return DataResponse.errorMsg(e.getMessage());
        }
        if (isSuccess) {
            return DataResponse.ok("商户订单创建成功！");
        } else {
            return DataResponse.errorMsg("商户订单创建失败，请重试...");
        }
    }

    /**
     * 商户订单创建入参校验.
     */
    private void check(MerchantOrdersDto merchantOrdersDto) {
        // 订单id
        String merchantOrderId = merchantOrdersDto.getMerchantOrderId();
        // 用户id
        String merchantUserId = merchantOrdersDto.getMerchantUserId();
        // 实际支付订单金额
        Integer amount = merchantOrdersDto.getAmount();
        // 支付方式
        Integer payMethod = merchantOrdersDto.getPayMethod();
        // 支付成功后的回调地址（自定义）
        String returnUrl = merchantOrdersDto.getReturnUrl();

        if (StringUtils.isBlank(merchantOrderId)) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[orderId]不能为空");
        }
        if (StringUtils.isBlank(merchantUserId)) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[userId]不能为空");
        }
        if (amount == null || amount < 1) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[realPayAmount]不能为空并且不能小于1");
        }
        if (payMethod == null) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[payMethod]不能为空并且不能小于1");
        }
        if (!payMethod.equals(PayMethod.WEIXIN.type) && !payMethod.equals(PayMethod.ALIPAY.type)) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[payMethod]目前只支持微信支付或支付宝支付");
        }
        if (StringUtils.isBlank(returnUrl)) {
            throw new AppException(CommonError.RequestParamsInvalid, "参数[returnUrl]不能为空");
        }
    }

    /**
     * 提供给大家查询的方法，用于查询订单信息.
     *
     * @param merchantOrderId 订单号
     * @param merchantUserId  用户ID
     * @return 订单信息
     */
    @GetMapping("getPaymentCenterOrderInfo")
    @Operation(summary = "查询订单信息,测试使用")
    public BaseResponse getPaymentCenterOrderInfo(@Parameter(description = "商户订单号") String merchantOrderId,
                                                  @Parameter(description = "商户用户Id") String merchantUserId) {
        if (StringUtils.isBlank(merchantOrderId) || StringUtils.isBlank(merchantUserId)) {
            return DataResponse.errorMsg("查询参数不能为空！");
        }
        PayOrders orderInfo = paymentOrderService.queryOrderInfo(merchantUserId, merchantOrderId);
        return DataResponse.ok(orderInfo);
    }


    /**
     * 微信扫码支付页面
     */
    @PostMapping(value = "/getWXPayQRCode")
    @Operation(summary = "微信扫码支付页面获取支付二维码")
    public BaseResponse getWXPayQRCode(@Parameter(description = "商户订单号") String merchantOrderId,
                                       @Parameter(description = "商户用户Id") String merchantUserId) throws Exception {
        log.info(wxPayConfig.toString());
        // 根据订单ID和用户ID查询订单详情
        PayOrders waitPayOrder = paymentOrderService.queryOrderByStatus(merchantUserId,
                merchantOrderId, PaymentStatus.WAIT_PAY.type);

        // 商品描述.
        String body = "xiao天鹅-付款用户[" + merchantUserId + "]";
        // 商户订单号.
        String outTradeNo = merchantOrderId;
        // 从redis中去获得这笔订单的微信支付二维码，如果订单状态没有支付没有就放入，这样的做法防止用户频繁刷新而调用微信接口
        if (waitPayOrder != null) {
            String qrCodeUrl = redisService.getCacheObject(wxPayConfig.getQrcodeKey() + ":" + merchantOrderId);
            if (StringUtils.isEmpty(qrCodeUrl)) {
                // 订单总金额，单位为分
                String totalFee = String.valueOf(waitPayOrder.getAmount());
                // 统一下单
                PreOrderResult preOrderResult = wxOrderService.placeOrder(body, outTradeNo, totalFee);
                qrCodeUrl = preOrderResult.getCode_url();
            }
            PaymentInfoVo paymentInfoVo = new PaymentInfoVo();
            paymentInfoVo.setAmount(waitPayOrder.getAmount());
            paymentInfoVo.setMerchantOrderId(merchantOrderId);
            paymentInfoVo.setMerchantUserId(merchantUserId);
            paymentInfoVo.setQrCodeUrl(qrCodeUrl);
            // redis缓存.
            redisService.setCacheObject(wxPayConfig.getQrcodeKey() + ":" + merchantOrderId, qrCodeUrl,
                    wxPayConfig.getQrcodeExpire(), TimeUnit.SECONDS);
            return DataResponse.ok(paymentInfoVo);
        } else {
            return DataResponse.errorMsg("该订单不存在，或已经支付");
        }
    }


    /**
     * 前往支付宝进行支付.
     *
     * @param merchantOrderId 订单号
     * @param merchantUserId  用户id
     * @return BaseResponse
     */
    @ResponseBody
    @Operation(summary = "跳转支付宝扫码支付页面")
    @RequestMapping(value = "/goAlipay", method = RequestMethod.POST)
    public BaseResponse goAlipay(@Parameter(description = "商户订单号") String merchantOrderId,
                                 @Parameter(description = "商户用户Id") String merchantUserId) {
        // 查询订单详情
        PayOrders waitPayOrder = paymentOrderService.queryOrderByStatus(merchantUserId, merchantOrderId, PaymentStatus.WAIT_PAY.type);
        if (waitPayOrder == null) {
            return DataResponse.errorMsg("订单不存在！！");
        }
        //获得初始化的AlipayClient
        AlipayClient alipayClient =
                new DefaultAlipayClient(aliPayConfig.getGatewayUrl(),
                        aliPayConfig.getAppId(),
                        aliPayConfig.getMerchantPrivateKey(),
                        "json",
                        aliPayConfig.getCharset(),
                        aliPayConfig.getAlipayPublicKey(),
                        aliPayConfig.getSignType());

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(aliPayConfig.getReturnUrl());
        alipayRequest.setNotifyUrl(aliPayConfig.getNotifyUrl());
        // 商户订单号, 商户网站订单系统中唯一订单号, 必填
        String out_trade_no = merchantOrderId;
        // 付款金额, 必填 单位元  注意区别微信支付的单位是  "分"
        String total_amount = String.valueOf(Double.valueOf(waitPayOrder.getAmount()) / 100);
        // 订单名称, 必填
        String subject = "小鹅-付款用户[" + merchantUserId + "]";
        // 商品描述, 可空, 目前先用订单名称
        String body = subject;
        // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
        String timeout_express = "1d";
        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                + "\"total_amount\":\"" + total_amount + "\","
                + "\"subject\":\"" + subject + "\","
                + "\"body\":\"" + body + "\","
                + "\"timeout_express\":\"" + timeout_express + "\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        // 请求
        String alipayForm = "";
        try {
            alipayForm = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        log.info("支付宝支付 - 前往支付页面, alipayForm: \n{}", alipayForm);
        return DataResponse.ok(alipayForm);
    }

}
